﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;

namespace PlanB.Core.Logging
{
    /// <summary>
    /// Class which is used to configure the PlanB.Core logger. 
    /// It can be read from the .config files, or created manually with the configuration information
    /// </summary>
    public class LoggingConfiguration : ConfigurationSection
    {
        #region Examples
        /*
        
         ADD FOLLOWING sectionGroup and section into .config file's <configSections> node, depending if it is app.config or web.config:
         ==============================================================================================================================
         
         <configSections>
            <sectionGroup name="PlanB">
              <section name="Logging" type="PlanB.Core.Logging.Configuration,PlanB.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=79ea5ba3438af0bf"></section> <!-- This is for web.config -->
              <section name="Logging" type="PlanB.Core.Logging.Configuration,PlanB.Core"></section> <!-- This is for app.config -->
            </sectionGroup>
          </configSections>
          
          
         <configSections>
          
           ...
            <sectionGroup name="PlanB">
              <section name="Logging" type="PlanB.Core.Logging.Configuration,PlanB.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=79ea5ba3438af0bf"></section> <!-- This is for web.config -->
              <section name="Logging" type="PlanB.Core.Logging.Configuration,PlanB.Core"></section> <!-- This is for app.config -->
            </sectionGroup>
            ...
         
          </configSections>

         
          <PlanB>
            <Logging>
              <LoggingImplementation
                name="Mock Logger"
                type="PlanB.Core.Logging.MockLogger,PlanB.Core" /> <!-- Set here the logging implementation -->
              <LoggingSettings
                  traceLevel="Verbose" 
                  eventId="1-9999"
                  innerExceptions="All"
              />
              <LoggerParameters> <!-- Set here the implementation specific logging parameters, they are different for different implementations -->
                <add name="LoggingServerName" value="TestServer" />
                <add name="B" value="C:\foo1" />
              </LoggerParameters>
            </Logging>
          </PlanB>
         
         */
        #endregion


        /// <summary>
        /// Logging implementation used in the application.
        /// </summary>
        [ConfigurationProperty("LoggingImplementation")]
        public LoggingImplementation LoggingImplementation
        {
            get { return ((LoggingImplementation)(base["LoggingImplementation"])); }
        }

        /// <summary>
        /// Logging implementation used in the application.
        /// </summary>
        [ConfigurationProperty("LoggingSettings")]
        public LoggingSettings LoggingSettings
        {
            get { return ((LoggingSettings)(base["LoggingSettings"])); }
        }

        /// <summary>
        /// This property stores the parameters dictionary, which configure additional parameters for each logging implementation. 
        /// Since each logging implementation
        /// has it's own specific configuration issues (ULS is different than TXT logger), this section remains untypified, and each logging
        /// implementation needs to check if all of the required logging parameters are present there, and to throw a meaningfull exception if 
        /// they are not
        /// </summary>
        [ConfigurationProperty("LoggerParameters")]
        public LoggerParametersCollection LoggerParameters
        {
            get { return ((LoggerParametersCollection)(base["LoggerParameters"])); }
        }
    }

    
    
    
    /// <summary>
    /// LoggingImplementation is a configuration element used to specify the logger used in the application, for example ULS or TXT
    /// It has two properties: 
    /// Name - descriptive name of the logging implementation, like "Mock Implementation"
    /// Type - fully qualified class and assembly name, e.g. "PlanB.Core.Logging.MockLogger,PlanB.Core"
    /// </summary>
    public class LoggingImplementation : ConfigurationElement
    {
        /// <summary>
        /// LoggingImplementation name is free, descriptive name of the logger used, e.G. "SharePoint ULS Log"
        /// </summary>
        [ConfigurationProperty("name", DefaultValue = "", IsKey = true, IsRequired = false)]
        public string Name
        {
            get
            {
                return ((string)(base["name"]));
            }
            set
            {
                base["name"] = value;
            }
        }

        /// <summary>
        /// LoggingImplementation type is a class and assembly name of the logging implementation class
        /// Class needs to implement PlanB.Core.Logging.iLogger interface
        /// </summary>
        /// <example>PlanB.Core.Logging.MockLogger,PlanB.Core</example>
        [ConfigurationProperty("type", DefaultValue = "PlanB.Core.Logging.MockLogger,PlanB.Core", IsKey = false, IsRequired = true)]
        public string Type
        {
            get
            {
                return ((string)(base["type"]));
            }
            set
            {
                base["type"] = value;
            }
        }
    }

   

    /// <summary>
    /// LoggingSettings is a configuration element used to define the logging parameters which are common for each logging implementation - regardless if it is MOCK, TXT, ULS, EventLog etc
    /// 
    /// Logging settings common for each implementation are:
    /// traceLevel - Minimal trace level required for the event to be logged. This leaves to the admins to decide which level do they want to log. Values are from the PlanB.Core.Logging.EventServerity enum
    /// eventId="1-9999" - Admins can specify which range of events need to be logged
    /// innerExceptions - Defines the depth of the inner exceptions which will be stored into the log. The depth levels are read from the PlanB.Core.Logging.InnerExceptionsLevel enum
    /// </summary>
    public class LoggingSettings : ConfigurationElement
    {
        /// <summary>
        /// Minimal trace level required for the event to be logged. 
        /// This leaves to the admins the possibility to decide which level do they want to log. 
        /// Values are from the PlanB.Core.Logging.EventServerity enum
        /// </summary>
        [ConfigurationProperty("traceLevel", DefaultValue = "Verbose", IsKey = false, IsRequired = false)]
        public string TraceLevel
        {
            //TODO: Change typr to Enum
            get
            {
                return ((string)(base["traceLevel"]));
            }
            set
            {
                base["traceLevel"] = value;
            }
        }

        /// <summary>
        /// Range of the events which will be logged. Administrators can restrict logging only to the certain event / events. For example, if the data access exceptions are in the range between 5000 and 5999,
        /// setting the EventId property to 5000-5999 would make the logger to log only the DAL exceptions
        /// </summary>
        /// <example>*, 1-100, 10000</example>
        [ConfigurationProperty("eventId", DefaultValue = "*", IsKey = false, IsRequired = false)]
        public string EventId
        {
            get
            {
                return ((string)(base["eventId"]));
            }
            set
            {
                base["eventId"] = value;
            }
        }

        /// <summary>
        /// Defines which depth of Inner Exceptions will be logged
        /// The depth levels are read from the PlanB.Core.Logging.InnerExceptionsLevel enum
        /// Possible values: None (no inner exceptions), All (all inner exceptions, unlimited depth), First (only the first inner Exception will be logged)
        /// </summary>
        /// <example>All</example>
        [ConfigurationProperty("innerExceptions", DefaultValue = "All", IsKey = false, IsRequired = false)]
        public string InnerExceptions
        {
            //TODO: Change type to Enum
            get
            {
                return ((string)(base["innerExceptions"]));
            }
            set
            {
                base["innerExceptions"] = value;
            }

        }
    }




    /// <summary>
    /// The collection class that will store the list of each element/item that
    /// is returned back from the configuration manager
    /// </summary>
    [ConfigurationCollection(typeof(LoggingParameter))]
    public class LoggerParametersCollection : ConfigurationElementCollection
    {
        /// <summary>
        /// Overrudes standard CreateNewElement method to return new LoggingParameter
        /// </summary>
        /// <returns></returns>
        protected override ConfigurationElement CreateNewElement()
        {
            return new LoggingParameter();
        }

        /// <summary>
        /// Overides the standard GetElementKey method to return the logging parameter
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((LoggingParameter)(element)).Name;
        }

        /// <summary>
        /// Defines standard indexer
        /// </summary>
        /// <param name="idx"></param>
        /// <returns></returns>
        public LoggingParameter this[int idx]
        {
            get
            {
                return (LoggingParameter)BaseGet(idx);
            }
        }
    }

    /// <summary>
    /// Each single logging parameter must contain two properties: name and value
    /// </summary>
    public class LoggingParameter : ConfigurationElement
    {
        /// <summary>
        /// Logging parameter name
        /// </summary>
        [ConfigurationProperty("name", DefaultValue = "", IsKey = true, IsRequired = true)]
        public string Name
        {
            get
            {
                return ((string)(base["name"]));
            }
            set
            {
                base["name"] = value;
            }
        }

        /// <summary>
        /// Logging parameter value
        /// </summary>
        [ConfigurationProperty("value", DefaultValue = "", IsKey = false, IsRequired = false)]
        public string Value
        {
            get
            {
                return ((string)(base["value"]));
            }
            set
            {
                base["value"] = value;
            }

        }
    }
}
